package com.apobates.jforum2.troll.nest.controller;

import com.apobates.jforum2.troll.actionlog.stub.vo.BoardActionVo;
import com.apobates.jforum2.troll.forum.stub.vo.BoardCaseGroupVo;
import com.apobates.jforum2.troll.forum.stub.vo.BoardCollectStatsVo;
import com.apobates.jforum2.troll.forum.stub.vo.BoardConfigVo;
import com.apobates.jforum2.troll.forum.stub.vo.BoardModelVo;
import com.apobates.jforum2.troll.forum.stub.vo.BoardStatsCollectVo;
import com.apobates.jforum2.troll.forum.stub.vo.BoardStatsVo;
import com.apobates.jforum2.troll.forum.stub.vo.BoardVo;
import com.apobates.jforum2.troll.nest.service.ActionLogClient;
import com.apobates.jforum2.troll.nest.service.BoardClient;
import com.apobates.jforum2.troll.nest.vo.BoardRecordVo;
import com.apobates.jforum2.troll.nest.vo.BoardUnionCheckVo;
import com.apobates.jforum2.troll.utils.core.Commons;
import com.apobates.jforum2.troll.utils.core.DateTimeUtils;
import com.apobates.jforum2.troll.utils.core.EntityPageResult;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.http.MediaType;

/**
 * 版块服务API控制器
 * @author xiaofanku
 * @since 20210413
 */
@RestController
@RequestMapping("/api/board")
public class BoardClientController {
    @Autowired
    private BoardClient boardClient;
    @Autowired
    private ActionLogClient actionLogClient;
    
    //1:版块列表底部的统计
    @GetMapping("/collect")
    public BoardStatsCollectVo getCollectStats(@RequestParam(value="cycle", required=false, defaultValue="30") int statsCycle){
        ResponseEntity<BoardStatsCollectVo> rs = boardClient.getCollectStats(statsCycle);
        return Optional.ofNullable(rs.getBody()).orElse(BoardStatsCollectVo.empty(statsCycle+""));
    }
    
    //2:指定的版块
    @GetMapping("/{id}")
    public BoardVo get(@PathVariable("id")long boardId){
        ResponseEntity<BoardVo> bv = boardClient.get(boardId);
        return Optional.ofNullable(bv.getBody()).orElse(new BoardVo());
    }
    
    //3:指定版块的图标
    @GetMapping("/{id}/ico/{scale}")
    public String getIco(@PathVariable("id")long boardId, @PathVariable("scale")String scale){
        ResponseEntity<String> rs = boardClient.getIco(boardId, scale);
        return Optional.ofNullable(rs.getBody()).orElse("/ico/default_icon.png");
    }
    
    //4:指定版块组下的所有版块
    @GetMapping("/all/{volume}")
    public List<BoardVo> getAllBoardsByVolume(@PathVariable("volume")int boardGroupId){
        return boardClient.getAllBoardsByVolume(boardGroupId);
    }
    
    //5:所有可用的版块
    @GetMapping("/all")
    public List<BoardVo> getAll(){
        return boardClient.getAll();
    }
    
    //6:指定的版块[并加载版块的统计]
    @GetMapping("/{id}/cascade/stats")
    public BoardCollectStatsVo getBoardStatsById(@PathVariable("id")long boardId){
        ResponseEntity<BoardCollectStatsVo> rs = boardClient.getBoardStatsById(boardId);
        return Optional.ofNullable(rs.getBody()).orElse(new BoardCollectStatsVo());
    }
    
    //7:查看指定版块的统计
    @GetMapping("/{id}/stats")
    public BoardStatsVo getStats(@PathVariable("id")long boardId){
        ResponseEntity<BoardStatsVo> rs = boardClient.getStats(boardId);
        return Optional.ofNullable(rs.getBody()).orElse(new BoardStatsVo());
    }
    
    //8:查看多个版块的统计并填充今日话题数
    @PostMapping(value="/stats/multi", consumes="application/x-www-form-urlencoded")
    public List<BoardStatsVo> getMultiStats(@RequestParam("records")String boardIdString){
        return boardClient.getMultiStats(boardIdString);
    }
    
    //9:所有的版块统计记录
    @GetMapping("/stats/all")
    public List<BoardStatsVo> getAllStats(){
        return boardClient.getAllStats();
    }
    
    //10:查看指定版块并及联加载版块组
    @GetMapping("/{id}/volume/{volume}")
    public BoardCaseGroupVo getBoardCascadeBoardGroup(@PathVariable("id")long boardId, @PathVariable("volume")int boardGroupId){
        ResponseEntity<BoardCaseGroupVo> rs = boardClient.getBoardCascadeBoardGroup(boardId, boardGroupId);
        return Optional.ofNullable(rs.getBody()).orElse(new BoardCaseGroupVo());
    }
    
    //11:指定的会员是否收藏过版块
    @GetMapping("/{id}/favorite/member/{member}")
    public boolean isFavoriteBoard(@PathVariable("id")long boardId, @PathVariable("member")long memberId){
        return boardClient.isFavoriteBoard(boardId, memberId);
    }
    
    //12:联合检查:
    //联合检查:
    // 1)是否可以收藏, 可以返回true
    //Angular采用的
    @GetMapping(value="/{id}/check/{member}/operate", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter getThreadsUnionResult(@PathVariable("id") long boardId, @PathVariable("member") long memberId) {
        SseEmitter emitter = new SseEmitter(12000L);
        try {
            SseEmitter.SseEventBuilder event = SseEmitter.event()
                    .data(queryBoardUnionOperate(boardId, memberId))
                    .id(DateTimeUtils.getUnixTimestamp()+""+Commons.randomNumeric(4))
                    .name("BoardUnionCheck");
            emitter.send(event);
        } catch (Exception ex) {
            emitter.completeWithError(ex);
        } finally {
            emitter.complete();
        }
        return emitter;
    }

    //-----------------------------------------------BoardController
    //13:查看指定会员收藏的版块并加载版块的统计
    @GetMapping("/favorite/member/{member}")
    public List<BoardCollectStatsVo> getMemberFavoriteBoards(@PathVariable("member") long memberId, @RequestParam("size") int showSize){
        Set<Long> boardIdSet = actionLogClient.getMemberFavoriteBoard(memberId, showSize).stream().map(BoardActionVo::getBoardId).collect(Collectors.toSet());
        List<BoardCollectStatsVo> rs = boardClient.getMultiBoardAndStats(Commons.longToString(boardIdSet));
        return rs;
    }
    
    //14:查看指定会员收藏的版块并解码版块图标地址
    @GetMapping("/star/member/{member}")
    public List<BoardVo> getMemberFavoriteBoardsNoStats(
            @PathVariable("member") long memberId,
            @RequestParam("size") int showSize,
            @RequestParam("scale")String scale){
        Set<Long> boardIdSet = actionLogClient.getMemberFavoriteBoard(memberId, showSize).stream().map(BoardActionVo::getBoardId).collect(Collectors.toSet());
        List<BoardVo> rs = boardClient.getMultiBoardAndDecodeIco(Commons.longToString(boardIdSet), scale);
        return rs;
    }
    
    //15:分页查看指定会员收藏的版块
    @GetMapping("/favorite/member/{member}/{page}/{number}")
    public EntityPageResult<BoardRecordVo> getMemberFavorites(@PathVariable("member") long memberId, @PathVariable("page") int page, @PathVariable("number") int pageSize){
        EntityPageResult<BoardActionVo> rs = actionLogClient.getMemberFavoriteBoard(memberId, page, pageSize);
        Set<Long> boardIdSet = rs.getResult().stream().map(BoardActionVo::getBoardId).collect(Collectors.toSet());
        final Map<Long,BoardVo> boardData = boardClient.getMultiBoard(Commons.longToString(boardIdSet)).stream().collect(Collectors.toMap(BoardVo::getId, Function.identity()));
        Stream<BoardRecordVo> tmp = rs.getResult().stream().map(bav->boardActionMapper().apply(bav, boardData.getOrDefault(bav.getBoardId(), new BoardVo())));
        return EntityPageResult.<BoardRecordVo>of(rs.getTotal(), rs.getPage(), rs.getSize(), tmp);
    }

    //16:收藏
    @PutMapping(value="/{id}/favorite", consumes="application/x-www-form-urlencoded")
    public boolean favorite(
            @PathVariable("id")long boardId,
            @RequestParam("member")long memberId,
            @RequestParam("nickname") String memberNickname,
            @RequestParam("token") String token,
            @RequestParam("ip")String ipAddr){
        return boardClient.favorite(boardId, memberId, memberNickname, token, ipAddr);
    }
    
    //17:取消收藏
    @PutMapping(value="/{id}/favorite/cancel", consumes="application/x-www-form-urlencoded")
    public boolean cancelFavorite(
            @PathVariable("id")long boardId,
            @RequestParam("member")long memberId,
            @RequestParam("nickname") String memberNickname,
            @RequestParam("token") String token,
            @RequestParam("ip")String ipAddr){
        return boardClient.cancelFavorite(boardId, memberId, memberNickname, token, ipAddr);
    }
    
    //18:锁定
    @PutMapping(value="/{id}/lock", consumes="application/x-www-form-urlencoded")
    public boolean locked(
            @PathVariable("id")long boardId,
            @RequestParam("volume")int boardGroupId,
            @RequestParam("member")long memberId,
            @RequestParam("nickname") String memberNickname,
            @RequestParam("token") String token,
            @RequestParam("ip")String ipAddr){
        return boardClient.locked(boardId, boardGroupId, memberId, memberNickname, token, ipAddr);
    }
    
    //19:解锁
    @PutMapping(value="/{id}/lock/cancel", consumes="application/x-www-form-urlencoded")
    public boolean cancelLock(
            @PathVariable("id")long boardId,
            @RequestParam("volume")int boardGroupId,
            @RequestParam("member")long memberId,
            @RequestParam("nickname") String memberNickname,
            @RequestParam("token") String token,
            @RequestParam("ip")String ipAddr){
        return boardClient.cancelLock(boardId, boardGroupId, memberId, memberNickname, token, ipAddr);
    }
    
    //20:查看指定版块的配置文件
    @GetMapping("/{id}/config")
    public BoardConfigVo getConfig(@PathVariable("id")long boardId){
        ResponseEntity<BoardConfigVo> rs = boardClient.getConfig(boardId);
        return Optional.ofNullable(rs.getBody()).orElse(new BoardConfigVo());
    }
    
    //21:版块Top榜
    @GetMapping("/model")
    public List<BoardModelVo> getTopBoard(){
        return boardClient.getTopBoard();
    }
    
    private static BiFunction<BoardActionVo, BoardVo, BoardRecordVo> boardActionMapper(){
        return (bav, bv)->{
            BoardRecordVo brv = new BoardRecordVo();
            brv.setId(bav.getBoardId());
            brv.setTitle(bv.getTitle());
            brv.setLink(bv.getLink());
            brv.setDescription(bv.getDescription());
            //
            brv.setAction(bav.getAction());
            brv.setActionTitle(bav.getActionTitle());
            //
            brv.setEntryDateTime(bav.getEntryDateTime());
            brv.setDate(DateTimeUtils.formatClock(bav.getEntryDateTime()));
            return brv;
        };
    }

    private BoardUnionCheckVo queryBoardUnionOperate(long boardId, long memberId){
        BoardUnionCheckVo rs = new BoardUnionCheckVo();
        rs.setId(boardId);
        rs.setFavorite(boardClient.isFavoriteBoard(boardId, memberId)?"1":"0");
        return rs;
    }
}